#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>
#include <time.h>
#include "des.h"

#define TGS_PORT 13579

char K_TGS[] = "INTGS000"; //由TGS和AS管理预先商定
char K_SS[] = "INSS0000"; //由SS和TGS预先商定
char Ksession_Client_SS[] = "Session2"; //Client和SS之间认证的对话密钥

void serve(struct sockaddr_in *clientAddr, int client)
{
    int i;
    int iDataNum = -1;
    char C[200]; // 存放由client发送过来的消息C
    char D[200]; // 存放由client发送过来的消息D
    char E[200]; // 发送的加密消息E
    char F[200]; // 发送的加密消息F

    char ServiceID[100]; //SS服务器的ID
    char Ksession_Client_TGS[100]; //客户和TGS服务器会话的密钥
    char ClientID1[100];//消息C中的客户的ID
    char ClientID2[100]; //消息D中的客户的ID
    char client_net_addr[100];//客户的网络地址
    time_t timestamp1 = 0;
    time_t timestamp2 = 0;

    //inet_ntoa ip地址转换函数，将网络字节序IP转换为点分十进制IP
    //表达式：char *inet_ntoa (struct in_addr);
    printf("IP is %s\n", inet_ntoa(clientAddr->sin_addr));
    printf("Port is %d\n", htons(clientAddr->sin_port));
    printf("等待消息...\n");

    printf("开始读取消息C\n");
    int LenOfC = recv(client, C, 200, 0);
    // printf("%d\n",LenOfC);
    C[LenOfC] = 0;

    printf("开始读取消息D\n");
    char tempD[200];
    int LenOfD = recv(client,tempD,200,0);
    tempD[LenOfD] = 0;
    // printBase64(D);

    printf("解密消息C\n");
    char tempB[200];
    char B[200];
    // for(i = 0;i<strlen(C);i++){
    //     printf("%c ",C[i]);
    //     if(i%10 == 9){
    //         printf("\n");
    //     }
    // }

    sscanf(C,"%[^,],%s",ServiceID,tempB);
    //为了防止有\0的出现，需要重新赋值
    for(i = strlen(ServiceID)+1 ; i<LenOfC;i++){
        // printf("%d\n",i);
        tempB[i-(strlen(ServiceID)+1)] = C[i];
    }
    tempB[LenOfC-(strlen(ServiceID)+1)] = 0;
    // printf("serviceID = %s\n",ServiceID);
    // printf("len of temp B = %d\n",strlen(tempB));
    // printBase64(tempB);
    // printf("\n");
    //解密消息B
    rdes(K_TGS,tempB,(LenOfC-strlen(ServiceID)-1),B);
    // printf("%s\n",B);
    sscanf(B,"<%[^,],%[^,],%ld,%[^>]>",ClientID1,client_net_addr,&timestamp1,Ksession_Client_TGS);
    printf("消息C %s <%s,%s,%ld,%s>\n",ServiceID,ClientID1,client_net_addr,timestamp1,Ksession_Client_TGS);
    printf("Get Ksession_Client_TGS %s\n",Ksession_Client_TGS);

    //解密消息D
    printf("解密消息D\n");
    rdes(Ksession_Client_TGS,tempD,LenOfD,D);
    sscanf(D,"<%[^,],%ld,>",ClientID2,&timestamp2);
    printf("消息D <%s,%ld>\n",ClientID2,timestamp2);
    
    // printf("%s",ClientID1);
    // printf("%s",ClientID2);

    //认证的过程
    if(strcmp(ClientID1,ClientID2)!=0){
        printf("客户的ID不符合 认证失败\n");
        send(client, "Invalid ID", strlen("Invalid ID"), 0);
        return;
    }
    if(timestamp2 > timestamp1){
        printf("认证失败 TGT已过期\n");
        send(client, "Invalid TGT", strlen("Invalid TGT"), 0);
        return;
    }
    printf("-----TGS认证完成 开始向客户端发送消息-----\n");

    //生成消息E
    printf("生成消息E 消息E包括ServiceID和ST\n");
    char tempST[200];
    char ST[200];
    printf("ServiceID %s",ServiceID);
    sprintf(tempST,"<%s,%s,%ld,%s>",ClientID1,client_net_addr,timestamp2,Ksession_Client_SS);
    printf("ST %s\n",tempST);
    int LenOfST = des(K_SS,tempST,strlen(tempST),ST);
    // printf("ST is ");
    // printBase64(ST);
    // printf("\n");
    sprintf(E,"%s,%s",ServiceID,ST);
    printf("发送加密消息E\n");
    int lenOfE = strlen(ServiceID)+1+LenOfST;
    E[lenOfE] = 0;
    // printf("加密后的消息E ");
    // printBase64(E);
    // printf("\n");
    send(client,E,lenOfE,0);
    printf("发送完成\n");

    //发送消息E和F之间休息2秒，确保客户端接收
    sleep(2);

    //生成消息F
    printf("生成消息F\n");
    printf("发送加密消息F 明文是%s\n",Ksession_Client_SS);
    int lenOfF = des(Ksession_Client_TGS,Ksession_Client_SS,strlen(Ksession_Client_SS),F);
    F[lenOfF] = 0;
    // printf("加密后的消息F ");
    // printBase64(F);
    // printf("\n");
    send(client,F,lenOfF,0);
    printf("发送完成\n");

    printf("----------TGS发送消息完成----------\n");

}


int main(int argc, char *argv[])
{
    srand(time(NULL)+1);
    int client;
    int TGSSocket;
    pid_t pid;
    int addr_len = sizeof(struct sockaddr_in);
    struct sockaddr_in TGServer_addr;

    //socket函数，失败返回-1
    //int socket(int domain, int type, int protocol);
    //第一个参数表示使用的地址类型，一般都是ipv4，AF_INET
    //第二个参数表示套接字类型：tcp：面向连接的稳定数据传输SOCK_STREAM
    //第三个参数设置为0
    if ((TGSSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("Create socket error!\n");
        return 1;
    }
    else
    {
        printf("Socket number = %d\n", TGSSocket);
    }

    //初始化服务器端的套接字
    bzero(&TGServer_addr, sizeof(TGServer_addr));
    TGServer_addr.sin_family = AF_INET;                //TCP/IP协议
    TGServer_addr.sin_port = htons(TGS_PORT);           //绑定端口号，htons即host-to-network
    TGServer_addr.sin_addr.s_addr = htonl(INADDR_ANY); //服务器接受的任意内外网IP
    if (bind(TGSSocket, (struct sockaddr *)&TGServer_addr, sizeof(TGServer_addr)) < 0)
    {
        perror("connect");
        return 0;
    }
    else
    {
        printf("bind succeed\n");
    }
    listen(TGSSocket, 100);
    printf("TGS is Listening %d\n",TGS_PORT);
    while (1)
    {
        //调用accept函数后，会进入阻塞状态
        //accept返回一个套接字的文件描述符，这样服务器端便有两个套接字的文件描述符，
        //serverSocket和client。
        //serverSocket仍然继续在监听状态，client则负责接收和发送数据
        //clientAddr是一个传出参数，accept返回时，传出客户端的地址和端口号
        //addr_len是一个传入-传出参数，传入的是调用者提供的缓冲区的clientAddr的长度，以避免缓冲区溢出。
        //传出的是客户端地址结构体的实际长度。
        //出错返回-1

        struct sockaddr_in ClientAddr;
        client = accept(TGSSocket, (struct sockaddr *)&ClientAddr, (socklen_t *)&addr_len);
        // printf("client is %d\n", client);s
        if (client > 0)
        {
            printf("we have a new client\n");
        }
        pid = fork();
        if (pid == 0)
        { //返回子进程
            serve(&ClientAddr, client);
            return 0;
        }
    }
    close(TGSSocket);
    return 0;
}








